package cn.texous.util.commons.util;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import sun.font.FontDesignMetrics;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.ImageIcon;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Iterator;

/**
 * 图片处理工具
 *
 * @author liuyc
 * @time 2016年5月27日 上午10:18:00
 */
public class ImageUtils {

    private static final ImageUtils IMAGE_UTILS = new ImageUtils();

    private ImageUtils() {
    }

    /**
     * 截图
     *
     * @param srcFile      源图片、
     * @param targetFile   截好后图片全名、
     * @param startAcross  开始截取位置横坐标、
     * @param startEndlong 开始截图位置纵坐标、
     * @param width        截取的长，
     * @param hight        截取的高
     * @author liuyc
     * @time 2016年5月27日 上午10:18:23
     */
    public static void cutImage(String srcFile, String targetFile,
                                int startAcross, int startEndlong,
                                int width, int hight) throws Exception {
        // 取得图片读入器
        Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
        ImageReader reader = readers.next();
        // 取得图片读入流
        InputStream source = new FileInputStream(srcFile);
        ImageInputStream iis = ImageIO.createImageInputStream(source);
        reader.setInput(iis, true);
        // 图片参数对象
        ImageReadParam param = reader.getDefaultReadParam();
        Rectangle rect = new Rectangle(startAcross, startEndlong, width, hight);
        param.setSourceRegion(rect);
        BufferedImage bi = reader.read(0, param);
        ImageIO.write(bi, targetFile.split("\\.")[1], new File(targetFile));
    }

    /**
     * 图片拼接 （注意：必须两张图片长宽一致哦）
     *
     * @param files 要拼接的文件列表
     * @param type  横向拼接， 2 纵向拼接
     * @author liuyc
     * @time 2016年5月27日 下午5:52:24
     */
    public static void mergeImage(String[] files, int type, String targetFile) {
        int len = files.length;
        if (len < 1) {
            throw new RuntimeException("图片数量小于1");
        }
        File[] src = new File[len];
        BufferedImage[] images = new BufferedImage[len];
        int[][] imageArrays = new int[len][];
        for (int i = 0; i < len; i++) {
            try {
                src[i] = new File(files[i]);
                images[i] = ImageIO.read(src[i]);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            int width = images[i].getWidth();
            int height = images[i].getHeight();
            imageArrays[i] = new int[width * height];
            imageArrays[i] = images[i].getRGB(0, 0, width, height, imageArrays[i], 0, width);
        }
        int newHeight = 0;
        int newWidth = 0;
        for (int i = 0; i < images.length; i++) {
            // 横向
            if (type == 1) {
                newHeight = newHeight > images[i].getHeight() ? newHeight : images[i].getHeight();
                newWidth += images[i].getWidth();
                // 纵向
            } else if (type == 2) {
                newWidth = newWidth > images[i].getWidth() ? newWidth : images[i].getWidth();
                newHeight += images[i].getHeight();
            }
        }
        if ((type == 1 && newWidth < 1)
                || (type == 2 && newHeight < 1)) {
            return;
        }

        // 生成新图片
        try {
            BufferedImage imageNew = new BufferedImage(
                    newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
            int heightI = 0;
            int widthI = 0;
            for (int i = 0; i < images.length; i++) {
                if (type == 1) {
                    imageNew.setRGB(widthI, 0, images[i].getWidth(), newHeight, imageArrays[i], 0,
                            images[i].getWidth());
                    widthI += images[i].getWidth();
                } else if (type == 2) {
                    imageNew.setRGB(0, heightI, newWidth,
                            images[i].getHeight(), imageArrays[i], 0, newWidth);
                    heightI += images[i].getHeight();
                }
            }
            //输出想要的图片
            ImageIO.write(imageNew, targetFile.split("\\.")[1], new File(targetFile));

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 小图片贴到大图片形成一张图(合成)
     *
     * @author liuyc
     * @time 2016年5月27日 下午5:51:20
     */
    public static final void overlapImage(String bigPath, String smallPath, String outFile) {
        try {
            BufferedImage big = ImageIO.read(new File(bigPath));
            BufferedImage small = ImageIO.read(new File(smallPath));
            Graphics2D g = big.createGraphics();
            int x = (big.getWidth() - small.getWidth()) / 2;
            int y = (big.getHeight() - small.getHeight()) / 2;
            g.drawImage(small, x, y, small.getWidth(), small.getHeight(), null);
            g.dispose();
            ImageIO.write(big, outFile.split("\\.")[1], new File(outFile));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 大图上绘制小图
     *
     * @param big      大图
     * @param small    小图
     * @param x        x
     * @param y        y
     * @param compress 压缩
     */
    public static final void overlapImage(BufferedImage big,
                                          BufferedImage small, int x, int y, boolean compress) {
        OverLapImageParam param = OverLapImageParam.builder()
                .bigImg(big)
                .smallImg(small)
                .x(x)
                .y(y)
                .compressImg(compress)
                .build();

        overlapImage(param);
    }

    /**
     * 大图上绘制小图
     *
     * @param param 参数
     */
    public static final void overlapImage(OverLapImageParam param) {
        try {
            BufferedImage big = param.getBigImg();
            BufferedImage small = param.getSmallImg();
            Graphics2D g = big.createGraphics();
            if (param.getCompressImg()) {
                small = compressImg(small, big.getWidth(), big.getHeight());
            }
            g.drawImage(small, param.getX(), param.getY(),
                    small.getWidth(), small.getHeight(), null);
            g.dispose();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 压缩图片
     *
     * @param src    源
     * @param width  宽度
     * @param height 高度
     * @return
     */
    public static final BufferedImage compressImg(BufferedImage src, int width, int height) {
        int ow = src.getWidth();
        int oh = src.getHeight();
        if (ow > width || oh > height) {
            BigDecimal owb = new BigDecimal(ow);
            BigDecimal ohb = new BigDecimal(oh);
            BigDecimal widthScale = owb.divide(
                    new BigDecimal(width), 4, BigDecimal.ROUND_HALF_UP);
            BigDecimal heightScale = ohb.divide(
                    new BigDecimal(height), 4, BigDecimal.ROUND_HALF_UP);

            BigDecimal divideScale = heightScale;
            // 按宽度缩放
            if (widthScale.compareTo(heightScale) > 0)
                divideScale = widthScale;

            ow = owb.divide(divideScale, 0, BigDecimal.ROUND_HALF_UP).intValue();
            oh = ohb.divide(divideScale, 0, BigDecimal.ROUND_HALF_UP).intValue();
        }
        Image image = src.getScaledInstance(ow, oh, Image.SCALE_SMOOTH);
        BufferedImage tag = new BufferedImage(ow, oh, BufferedImage.TYPE_INT_RGB);
        Graphics g = tag.getGraphics();
        g.drawImage(image, 0, 0, null); // 绘制缩小后的图
        g.dispose();
        return tag;
    }

    /**
     * 给图片添加文字信息
     *
     * @author liuyc
     * @time 2016年5月31日 上午10:23:36
     */
    public static void drawStringForImage(String filePath, String content,
                                          Color contentColor, float qualNum, String targetFile) {
        ImageIcon imgIcon = new ImageIcon(filePath);
        Image theImg = imgIcon.getImage();
        int width = theImg.getWidth(null) == -1 ? 200 : theImg.getWidth(null);
        int height = theImg.getHeight(null) == -1 ? 200 : theImg.getHeight(null);
        BufferedImage bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = bimage.createGraphics();
        g.setColor(contentColor);
        g.setBackground(Color.red);
        g.drawImage(theImg, 0, 0, null);
        // 设置字体、字型、字号
        g.setFont(new Font(null, Font.BOLD, 13));
        // 写入文字
        g.drawString(content, 10, height / 2);
        g.dispose();
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(targetFile);
            ImageIO.write(bimage, targetFile.substring(targetFile.lastIndexOf(".") + 1), out);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    out = null;
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 获取文字图片
     *
     * @param param 参数
     * @return
     */
    public static final BufferedImage createFontImage(FontImageParam param) {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        String[] fontFamilies = ge.getAvailableFontFamilyNames();
        for (String s : fontFamilies) {
            System.out.println(s);
        }
        BufferedImage image = getBufferedImage(param.getWidth(),
                param.getHeight(), param.getTransparent());
        Graphics2D g = image.createGraphics();
        g.setColor(param.getBackgrountColor());
        g.fillRoundRect(0, 0, param.getWidth(),
                param.getHeight(), param.getArtWidth(), param.getArtWidth());
        g.setColor(param.getFontColor());
        //        g.setBackground(param.getBackgrountColor());
        //        g.drawImage(theImg, 0, 0, null);
        // 设置字体、字型、字号
        g.setFont(param.getFont());
        FontDesignMetrics metrics = FontDesignMetrics.getMetrics(param.getFont());
        int strWidth = metrics.stringWidth(param.getContent());
        int strHeight = metrics.getHeight();
        //左边位置
        int left = (param.getWidth() - strWidth) / 2;
        //顶边位置+上升距离（原本字体基线位置对准画布的y坐标导致字体偏上ascent距离，加上ascent后下移刚好顶边吻合）
        int top = (param.getHeight() - strHeight) / 2 + metrics.getAscent();
        // 写入文字
        g.drawString(param.getContent(), left, top);
        g.dispose();
        return image;
    }

    /**
     * 获取 buffered image
     *
     * @param width       宽度
     * @param height      高度
     * @param transparent 透明？
     * @return
     */
    public static final BufferedImage getBufferedImage(int width, int height,
                                                       boolean transparent) {

        BufferedImage bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        if (transparent) {
            Graphics2D gd = bimage.createGraphics();
            //设置透明  start
            bimage = gd.getDeviceConfiguration()
                    .createCompatibleImage(width, height, Transparency.TRANSLUCENT);
            //设置透明  end
        }
        return bimage;
    }

    /**
     * 获取中间位置
     *
     * @param big   大图
     * @param small 小图
     * @return
     */
    public static final int getCenterX(BufferedImage big, BufferedImage small) {
        int bigWidth = big.getWidth();
        int smallWidth = small.getWidth();
        return (bigWidth - smallWidth) >> 1;
    }

    public static final InputStream getInputStream(BufferedImage image) throws IOException {
        return getInputStream(image, "PNG");
    }

    /**
     * 获取输入流
     *
     * @param image      绘制的图片
     * @param formatName format name
     * @return return
     * @throws IOException exception
     */
    public static final InputStream getInputStream(
            BufferedImage image, String formatName) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = null;
        ImageOutputStream imageOutputStream = null;
        try {
            byteArrayOutputStream = new ByteArrayOutputStream();
            imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream);
            ImageIO.write(image, formatName, imageOutputStream);
            return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        } finally {
            if (byteArrayOutputStream != null)
                byteArrayOutputStream.close();
            if (imageOutputStream != null)
                imageOutputStream.close();
        }
    }

    private static final String getSuffix(String fileName) {
        return fileName.substring(fileName.lastIndexOf(".") + 1);
    }

    /**
     *
     */
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class OverLapImageParam {
        private BufferedImage bigImg;
        private BufferedImage smallImg;
        private boolean compressImg;
        private int x = 0;
        private int y = 0;

        public boolean getCompressImg() {
            return compressImg;
        }

    }

    /**
     *
     */
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class FontImageParam {
        // 宽度
        private int width;
        // 高度
        private int height;
        // 圆角大小
        private int artWidth;
        // 字体颜色
        private Color fontColor;
        // 背景颜色
        private Color backgrountColor;
        // 文字大小
        private Font font;
        // 文本内容
        private String content;
        // 是否透明背景
        private boolean transparent;

        public boolean getTransparent() {
            return transparent;
        }
    }

    /**
     * 绘制邀请码
     *
     * @param bigImage   背景
     * @param inviteCode 邀请码
     */
    public static void drawInviteCode(BufferedImage bigImage, String inviteCode) {
        int width = bigImage.getWidth();
        int fontBgWidth = width >> 1;
        int fontBgHeight = fontBgWidth / 5;
        System.out.println("fontBgWidth: " + fontBgWidth + ", fontBgHeight: " + fontBgHeight);

        Color fontBgColor = new Color(184, 0, 102, 179);
        Color fontColor = Color.white;
        Font font = new Font("黑体", Font.PLAIN, 65);

        FontImageParam param = FontImageParam.builder()
                .backgrountColor(fontBgColor)
                .content("邀请码：" + inviteCode)
                .fontColor(fontColor)
                .font(font)
                .height(fontBgHeight)
                .width(fontBgWidth)
                .artWidth(fontBgHeight)
                .transparent(true)
                .build();

        BufferedImage fontImage = createFontImage(param);

        OverLapImageParam overLapImageParam = new ImageUtils.OverLapImageParam();
        overLapImageParam.setBigImg(bigImage);
        overLapImageParam.setSmallImg(fontImage);
        overLapImageParam.setCompressImg(false);
        overLapImageParam.setX(getCenterX(bigImage, fontImage));
        overLapImageParam.setY(1300);
        ImageUtils.overlapImage(overLapImageParam);
    }

    public static void main(String[] args) {
        testCreateQr("/temp/test3.png");
    }

    /**
     * 测试二维码生成
     *
     * @param path 二维码内容
     */
    public static void testCreateQr(String path) {
        String bg = "";
        try {
            InputStream backgroundStream = HttpUtils.getInputStreamByUrl(bg);
            BufferedImage bigImage = ImageIO.read(backgroundStream);
            // 生成二维码链接规则需要确定
            String qrUrl = "https://www.baidu.com";
            BufferedImage qrcode = QRCodeUtils.createImage(qrUrl, null, 518, false);

            ImageUtils.OverLapImageParam overLapImageParam = new ImageUtils.OverLapImageParam();
            overLapImageParam.setBigImg(bigImage);
            overLapImageParam.setSmallImg(qrcode);
            overLapImageParam.setCompressImg(false);
            overLapImageParam.setX(getCenterX(bigImage, qrcode));
            overLapImageParam.setY(1450);
            ImageUtils.overlapImage(overLapImageParam);

            String inviteCode = "4534560";
            drawInviteCode(bigImage, inviteCode);

            File file = new File(path);
            if (!file.exists())
                file.createNewFile();
            ImageIO.write(bigImage, "PNG", file);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
